const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils

var EXPORTED_SYMBOLS = ["AntiChinaVideoAds"];

Cu.import("resource://gre/modules/NetUtil.jsm");

var Rules = {
    REFRULES: {
        'iqiyi': {
            're': 'http://www.iqiyi.com/',
            'find': /.*\.qiyi\.com/i
        },
        'youku': {
            're': 'http://www.youku.com/',
            'find': /http:\/\/.*\.youku\.com/i
        }
    }
};

var Preferences = {
    prefs: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).QueryInterface(Ci.nsIPrefBranch),
    getValue: function (name) {
        return Preferences.prefs.getComplexValue(name, Ci.nsISupportsString).data;
    },
    setValue: function (name, value) {
        var character = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
        character.data = value;
        Preferences.prefs.setComplexValue(name, Ci.nsISupportsString, character);
    },
    observe: function (subject, topic, data) {
        if (topic == "nsPref:changed") {
            Preferences.pending();
        }
    },
    pending: function () {
        try {
            Preferences.getValue("extensions.AntiChinaVideoAds.swfsource");
        } catch(e) {
            Preferences.setValue("extensions.AntiChinaVideoAds.swfsource", "https://coding.net/u/HalfLife/p/swf/git/raw/gh-pages/");
        }

        var setting = Preferences.getValue("extensions.AntiChinaVideoAds.swfsource");

//      SITES
        Rules.SITES = {
			'youku_loader': {
				'target': 'loader.swf',
				'find': /http:\/\/static\.youku\.com(\/v[\d\.]*)?\/v\/.*\/loaders?\.swf/i
			},
			'youku_player': {
				'target': 'player.swf',
				'find': /http:\/\/static\.youku\.com(\/v[\d\.]*)?\/v\/swf\/.*\/q?player.*\.swf/i
			},
			'tudou': {
				'target': 'tudou.swf',
				'find': /http:\/\/static\.youku\.com(\/v[\d\.]*)?\/v\/custom\/.*\/q?player.*\.swf/i
			},
			'iqiyi': {
				'target': 'iqiyi5.swf',
				'find': /https?:\/\/www\.iqiyi\.com\/(player\/\d+\/Player|common\/flashplayer\/\d+\/((Main)?Player_.*|[\d]{4}[a-z]+((?!aa|dc32).){6,7}))\.swf/i
			},
			'iqiy_out': {
				'target': 'iqiyi_out.swf',
				'find': /https?:\/\/www\.iqiyi\.com\/common\/flashplayer\/\d+\/SharePlayer_.*\.swf/i
			},
			'letvsdk': {
				'target': 'letvsdk.swf',
				'find': /http:\/\/player\.letvcdn\.com\/.*\/newplayer\/LetvPlayerSDK\.swf/i
			},
			'sohu_live': {
				'target': 'sohu_live.swf',
				'find': /https?:\/\/(tv\.sohu\.com\/upload\/swf\/(p2p\/)?\d+|(\d+\.){3}\d+\/wp8player)\/Main\.swf/i
			},
			'pptv': {
				'target': 'pptv.swf',
				'find': /http:\/\/player\.pplive\.cn\/ikan\/.*\/player4player2\.swf/i
			}
/*			'ku6': {
				'target': 'ku6.swf',
				'find': /http:\/\/player\.ku6cdn\.com\/default\/.*\/(v|player)\.swf/i
			},
			'ku6_out': {
				'target': 'ku6_out.swf',
				'find': /http:\/\/player\.ku6cdn\.com\/default\/out\/\d{12}\/player\.swf/i
			}*/
/*			'example3': {
				'method':'INLINE',
				're': [
								'playArea .player{height:auto}',
								'.vpactionv5_iframe_wrap{top:auto$1}.'
							],
				'match':[
								/\.playArea \.player{height:\d+px}/i,
								/ \.vpactionv5_iframe_wrap{top:\d+px(.*)}\./i
							],
				'find': /http:\/\/donotexist.com\/test.css/i
			}*/
		};
    }
};

function AntiChinaVideoAds() {};
AntiChinaVideoAds.prototype = {
        os: Cc['@mozilla.org/observer-service;1']
                .getService(Ci.nsIObserverService),
        init: function() {
            var site = Rules.SITES;
        },
        // getPlayer, get modified player
        getPlayer: function(site, callback) {
            NetUtil.asyncFetch(site['player'], function(inputStream, status) {
                var binaryOutputStream = Cc['@mozilla.org/binaryoutputstream;1']
                                            .createInstance(Ci['nsIBinaryOutputStream']);
                var storageStream = Cc['@mozilla.org/storagestream;1']
                                        .createInstance(Ci['nsIStorageStream']);
                var count = inputStream.available();
                var data = NetUtil.readInputStreamToString(inputStream, count);

                storageStream.init(512, count, null);
                binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));
                binaryOutputStream.writeBytes(data, count);

                site['storageStream'] = storageStream;
                site['count'] = count;

                if(typeof callback === 'function') {
                    callback();
                }
            });
        },
        getWindowForRequest: function(request){
            if(request instanceof Ci.nsIRequest){
                try{
                    if(request.notificationCallbacks){
                        return request.notificationCallbacks
                                    .getInterface(Ci.nsILoadContext)
                                    .associatedWindow;
                    }
                } catch(e) {}
                try{
                    if(request.loadGroup && request.loadGroup.notificationCallbacks){
                        return request.loadGroup.notificationCallbacks
                                    .getInterface(Ci.nsILoadContext)
                                    .associatedWindow;
                    }
                } catch(e) {}
            }
            return null;
        },
        observe: function(aSubject, aTopic, aData) {

			if (aTopic == "http-on-modify-request") {
				var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
				for(var i in Rules.REFRULES) {
					var rule = Rules.REFRULES[i];
					try {
						var URL = httpChannel.originalURI.spec;
						if(rule['find'].test(URL)) {
							httpChannel.referrer = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(rule['re'], null, null);
							httpChannel.setRequestHeader('Referer', rule['re'], false);
						}
					}
					catch(e) {}
				}
				return;
			}

            if(aTopic != 'http-on-examine-response') return;

            var http = aSubject.QueryInterface(Ci.nsIHttpChannel);

            for(var i in Rules.SITES) {
                var site = Rules.SITES[i];
                if(site['re'].test(http.URI.spec)) {
                    var fn = this, args = Array.prototype.slice.call(arguments);

                    if(typeof site['preHandle'] === 'function')
                        site['preHandle'].apply(fn, args);

                    if(!site['storageStream'] || !site['count']) {
                        http.suspend();
                        this.getPlayer(site, function() {
                            http.resume();
                            if(typeof site['callback'] === 'function')
                                site['callback'].apply(fn, args);
                        });
                    }

                    var newListener = new TrackingListener();
                    aSubject.QueryInterface(Ci.nsITraceableChannel);
                    newListener.originalListener = aSubject.setNewListener(newListener);
                    newListener.site = site;

                    break;
                }
            }
        },
        QueryInterface: function(aIID) {
            if(aIID.equals(Ci.nsISupports) || aIID.equals(Ci.nsIObserver))
                return this;

            return Cr.NS_ERROR_NO_INTERFACE;
        },
        register: function() {
            Preferences.pending();
            Preferences.prefs.addObserver("extensions.AntiChinaVideoAds.swfsource", Preferences, false);
            this.init();
            this.os.addObserver(this, 'http-on-examine-response', false);
            this.os.addObserver(this, 'http-on-modify-request', false);
        },
        unregister: function() {
            Preferences.prefs.removeObserver("extensions.AntiChinaVideoAds.swfsource", Preferences);
            this.os.removeObserver(this, 'http-on-examine-response', false);
            this.os.removeObserver(this, 'http-on-modify-request', false);
        }
    };

    // TrackingListener, redirect youku player to modified player
    function TrackingListener() {
        this.originalListener = null;
        this.site = null;
    }
    TrackingListener.prototype = {
        onStartRequest: function(request, context) {
            this.originalListener.onStartRequest(request, context);
        },
        onStopRequest: function(request, context) {
            this.originalListener.onStopRequest(request, context, Cr.NS_OK);
        },
        onDataAvailable: function(request, context) {
            this.originalListener.onDataAvailable(request, context, this.site['storageStream'].newInputStream(0), 0, this.site['count']);
        }
    };

